import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

/**
 * Created by IntelliJ IDEA.
 * User: elin11
 * Date: Jul 28, 2008
 * Time: 9:35:40 AM
 * To change this template use File | Settings | File Templates.
 */
public class fastaCombine {
// permutes and creates list of all peptide combinations
	
    public class CombinedSegment implements Segment{
    	// struct containing peptide group it belongs to and indices in the larger peptide list
        public peptideGroup pGroup;
        public int startInd;
        public int length;
        public double Mass;
        public short BZuncertainty;
        public CombinedSegment(int startInd, int length, peptideGroup p, short bzUn) {
            this.startInd = startInd;
            this.length = length;
            this.pGroup = p;
            this.BZuncertainty = bzUn;
        }
		@Override
		public short getBZUncertanties() {
			return BZuncertainty;
		}
		@Override
		public String getCallString() {
			return pGroup.getProteinName();
		}
		@Override
		public Double getMass() {
			return Mass;
		}
		@Override
		public String getSequence() {
			String tempString = "";
			for(int i = startInd;i<=startInd+length;i++){
				tempString+= massList.get(i).getSequence();
			}
			return tempString;
		}
		@Override
		public int getLength() {
			// TODO Auto-generated method stub
			return length+1;
		}
		
    }

    private ArrayList<SingleSegment> massList;
    private ArrayList<peptideGroup>pepGroups;
    private ArrayList<CombinedSegment> ComboList;
    private ArrayList<Rule> splitRulesList;
    private ArrayList<Segment> segList;
    private String fastaFileName;
    private String massConvertFile;
    private String splitRulesFile;
    private int ComboSize;

    
    public ArrayList<Segment> getSegmentList(){
    	return segList;
    }
    public int getComboSize() {
        return ComboSize;
    }

    public void setComboSize(int ComboSize) {
        this.ComboSize = ComboSize;
    }


    public ArrayList<SingleSegment> getSingleList() {
        return massList;
    }

    public static void main(String[] args)throws IOException{
    	// initial driver program
    	
    	
        BufferedWriter writer = new BufferedWriter(new FileWriter("C:/EclipseWorkspace/SampleOut.txt"));
        //need a writer to test structure and output
        
        String fastaname = "C:/EclipseWorkspace/Tester3.txt";
        // fasta file format, heading then sequence
        
        String aminoMasses = "C:/EclipseWorkspace/aminomassindexes.txt";
        // file containing a list of aminoacid mass indices
        
        String cutRules = "C:/EclipseWorkspace/trypsin.txt";
        // file containing pertinent cut rules
        
        int comboSize = 3;
        
        fastaCombine blargh = new fastaCombine(fastaname,aminoMasses,cutRules,comboSize);
        blargh.Create();
        Iterator<Segment> iter = blargh.getSegmentList().iterator();
        Segment tempSeg;
        long time = System.currentTimeMillis();
        
        while(iter.hasNext()){
            tempSeg = iter.next();
            DecimalFormat dF = new DecimalFormat();
            dF.applyPattern("00000.00000");
            writer.write(dF.format(tempSeg.getMass()) + "\t" +tempSeg.getBZUncertanties() + "\t" + tempSeg.getLength()+ "\t"+ tempSeg.getSequence()  + "\r\n");
        }
        System.out.println("number of Proteins: " + blargh.getPeptideList().size());
        
        System.out.println("size of total singleSegments: " + blargh.getSingleList().size());
        System.out.println("size of total ComboSegments: " + blargh.getComboList().size());       
        System.out.println("size of total Segment List: " + blargh.getSegmentList().size());
        System.out.println("Time Write Taken: " + (System.currentTimeMillis()-time));
        writer.close();
                
    }
    public fastaCombine(String fastaFile, String massIndexFile, String splitfile , int combinationSize) throws IOException {
    	//instantiates
    	massList = new ArrayList<SingleSegment>();
        pepGroups = new ArrayList<peptideGroup>();
        splitRulesList = new ArrayList<Rule>();
        segList = new ArrayList<Segment>();
        
        
        fastaFileName = fastaFile;
        massConvertFile = massIndexFile;
        splitRulesFile = splitfile;
        ComboSize = combinationSize;
    }
    public void Create() throws IOException{
    	// checks to see if all names are, existing, and calls
    	if(!fastaFileName.isEmpty() && !massConvertFile.isEmpty() && !splitRulesFile.isEmpty() && ComboSize>0){
    		if(readSplitRules()){
                if(generatePrimaryLists()){
                    generateComboLists();
                    massComboLists();
                }
            }
            segList.addAll(massList);
            segList.addAll(ComboList);
        }
    }
    public ArrayList<CombinedSegment> getComboList() {
        return ComboList;
    }
    public ArrayList<peptideGroup> getPeptideList(){
    	return pepGroups;
    }
    private void massComboLists() {
        Iterator<CombinedSegment> comboIter = ComboList.iterator();
        CombinedSegment tempCombo;
        double tempDouble = 0.0;
        while(comboIter.hasNext()){
            tempCombo = comboIter.next();
            for(int i = 0;i<=tempCombo.length;i++){
                tempDouble+= massList.get(tempCombo.startInd+i).getMass();
            }
            tempCombo.Mass = tempDouble;
            tempDouble = 0.0;
        }
    }

    private void generateComboLists(){
    	ArrayList<Integer> complicationIndices = new ArrayList<Integer>();
        ComboList = new ArrayList<CombinedSegment>();
        int pepGroupCount = 0;
        peptideGroup pGroup = pepGroups.get(pepGroupCount);
        pepGroupCount++;
        for(int i = 0;i<massList.size();i++){
        	if(massList.get(i).getStatus() < (-125)){
        		complicationIndices.add(i);
        	}
        }
        for(int i = 0;i<massList.size();i++){
        	if(i>pGroup.endIndex){    			
                pGroup = pepGroups.get(pepGroupCount);
                pepGroupCount++;
            }
            for(int j = 1;j<=ComboSize;j++){
            	if(i+j < massList.size()){
	            	if(sequenceStatusFlagCheck(i,j)){
	            		if(i+j<=pGroup.endIndex){
	            			 //System.out.println((i)+ " ,"+(j) +" :: "+(i+j));
	            		     ComboList.add(new CombinedSegment(i,j,pGroup,getComboBZUncertainty(i,j)));
	            		}
		        		
		                
	                }
            	}
            }
            
        }
    }
    private boolean sequenceStatusFlagCheck(int index, int length){
    	for(int i = index;i<index+length;i++){
    		if(massList.get(i).getStatus()<-125)
    			return false;
    	}
    	return true;
    }
    private byte getComboBZUncertainty(int index,int length){
    	// in case it's got one of the ambiguous aminoacid letters
    	byte counter = 0;
    	for(int i = index;i<index+length;i++){
    		counter+= (massList.get(i).getStatus()+125);
    	}
    	return counter;
    }
    private boolean generatePrimaryLists() throws IOException {
    	// generates the first list from the file, just straight reads from file and returns true if
    	// anything was read and false if nothing.
    	// stores things in temp and on the next iteration first action is to send to findsplits,
    	// loop will have last one left over, which is taken care of after loop.
       BufferedReader reader = new BufferedReader(new FileReader(fastaFileName));
        //Loop as long as there are input lines.
        String readline = null;
        String ProtName = reader.readLine();

        String Sequence = "";
        while ((readline =reader.readLine()) != null) {
        	// checks for > if yes then read in as the header, if no append onto the sequence
            if(readline.charAt(0) == '>'){
                findSplits(ProtName,Sequence);// calls findsplits on the previous combination
                ProtName = readline;  // generates the header for next entry
                Sequence = reader.readLine(); // reads the next line which would be the next sequence
            }else{
                Sequence = Sequence.concat(readline); // assuming if it's not a > keep appending to sequence
            }
        }
        findSplits(ProtName,Sequence); // for the last entry
        reader.close();

        if(!pepGroups.isEmpty())
            return true;
        else
            return false;
    }

    private void findSplits(String ProtName, String pepSequence)throws IOException{
    	/* goes through each protein and creates a peptide group for it,
    	start and end index of peptide groups are based on the massList array
    	pepgroups also contain original header information.
    	
    	end result is that you have a masslist with right masses for single split sequences
    	and an arraylist of peptide groups containing start and end indices and headerinformation
    	*/
        int pepGroupsBegIndex = massList.size(); // nothing else adds to massList so this is right place
        Iterator<Rule> splitRulesIter = splitRulesList.iterator();
        ArrayList<Integer> proteinCleaveIndices = new ArrayList<Integer>();
        int pepBegin = 0;
        int pepEnd = 0;
        //basically walks up the sequence and creates a list of split areas and throws into array,
        // headache to code and have running properly
        while(splitRulesIter.hasNext()){
            proteinCleaveIndices.addAll(splitRulesIter.next().cleaveIndices(pepSequence));
            // splitRulesIter.next is a Rule and this line accesses the cleaveIndices Function
            // which finds all the indices of teh cleavage sites within the peptide sequence
        }
        Integer[] PCIArray = new Integer[proteinCleaveIndices.size()];
        pepGroups.add(new peptideGroup(pepGroupsBegIndex, ProtName));

        PCIArray = proteinCleaveIndices.toArray(PCIArray);
        Arrays.sort(PCIArray);
        for(int i = 0;i<PCIArray.length;i++){
            pepEnd = (int)PCIArray[i];
            massList.add(new SingleSegment(pepSequence.substring(pepBegin,pepEnd),massConvertFile));
            pepBegin = pepEnd;
            massList.get(massList.size()-1).setPgroup(pepGroups.get(pepGroups.size()-1));
        }
        massList.add(new SingleSegment(pepSequence.substring(pepBegin,pepSequence.length()),massConvertFile));
        massList.get(massList.size()-1).setPgroup(pepGroups.get(pepGroups.size()-1));
        
        pepGroups.get(pepGroups.size()-1).setEndIndex(pepGroupsBegIndex+PCIArray.length);
            }
    private boolean readSplitRules() throws IOException {
    	// reads the splitrules from a file and yeah, it still has issues so i have to debug more
    	// very specific problem
    	
        BufferedReader reader = new BufferedReader(new FileReader(splitRulesFile));
        //Loop as long as there are input lines.
        String readline = null;
        Iterator<Rule> rulesIter;
        Rule tempRule;
        System.out.println("reading rules");
        while ((readline=reader.readLine()) != null) {
            if(readline.charAt(0)=='1'){
                if(readline.charAt(1) == '/'){
                	tempRule = new Rule(readline.substring(2), true);
                	if(!splitRulesList.contains(tempRule)){
                		System.out.println("false");
                		splitRulesList.add(tempRule);
                	}
                }else if (readline.charAt(1) == '\\'){
                	tempRule = new Rule(readline.substring(2), false);
                	if(!splitRulesList.contains(tempRule)){
                		splitRulesList.add(tempRule);
                	}
                }else{
                    return false;
                }
            }else if(readline.charAt(0)=='0') {
                rulesIter = splitRulesList.iterator();
                while(rulesIter.hasNext()){
                    tempRule = rulesIter.next();
                    if(readline.substring(1).contains(tempRule.regRule))
                        tempRule.addException(readline.substring(1));
                }
            }else{
                return false;
            }
        }
        reader.close();
        Iterator<Rule> iter = splitRulesList.iterator();
        while(iter.hasNext()){
        	tempRule = iter.next();
        	System.out.println(tempRule.regRule);
        }
        return true;
    }
}
